
/*
 * @项目名称: 模板开发
 * @FilePath: /meek/src/geometry/circle.js
 * @Author: kongxueyang@datatang.com
 * @Date: 2020-09-16T15:29:54+08:00
 * @LastEditors: yangxianghong@datatang.com
 * @LastEditTime: 2023-07-13 15:03:23
 * Copyright (c) 2018-2022 
 */
                                                    
/**
 * Created by zypc on 2016/11/13.
 */

import Geometry from './geometry'
import Extent from './extent'
import { distance, getLineCircleIntersection, inteceptCircleLineSeg } from './support/geometryutil'


export default class Circle extends Geometry {

  constructor (x, y, r) {
    super()

    this.x = x
    this.y = y
    this.r = r
    this.sAngle = 0
    this.eAngle = 2 * Math.PI
    this.counterclockwise = true
  }

  /**
   * 获取对象的几何类型
   *
   * @protected
   */
  get geometryType () { return Geometry.CIRCLE }

  /**
   * 获取点的最小外接矩形
   *
   * @note 点是没有最小外接矩形
   * @returns {null}
   */
  get extent () {
    return new Extent(this.x - this.r, this.y - this.r, this.x + this.r, this.y + this.r)
  }

  getArea() {
    return Math.PI * (this.r - 0.1) * (this.r - 0.1);
  }

  containsXY (x, y, opt = {}) {
    let length = Circle.getDistance([this.x, this.y], [x, y]);
    return length <= this.r;
  }

  /**
   * 更新x,y坐标值
   *
   * @method update
   * @param nx x新值
   * @param ny y新值
   */
  update (coordinates) {
    ['x', 'y', 'r'].forEach((key, index) => {
      if (coordinates[index] !== undefined) {
        this[key] = coordinates[index];
      }
    })
    this._extent = null
  }
  
  /**
   *
   *
   * getFlatInteriorPoint
   * @returns {[]}
   */
  getFlatInteriorPoint () {
    return [this.x, this.y - this.r];
  }
  
  getCoordinates () {
    return [this.x, this.y, this.r];
  }

  /**
   * 设置点的坐标
   *
   * @method setCoordinates
   * @param coordinates
   */
  setCoordinates (coordinates) {
    this.update(coordinates)
    this.changed()
  }
  
  
  /**
   * 判断两个图形对象是否相等
   *
   * 判断标准：该图形的所有顶点值是否一致
   *
   * @method equal
   * @param geometry
   * @return {Boolean}
   */
  equal (geom) {
    let equals = false
    if (geom !== null) {
      return this.x === geom.x && this.y === geom.y && this.r === geom.r;
    }
    return equals
  }
  
  /**
   * 克隆点
   *
   * @method clone
   * @returns {Point}
   */
  clone () {
    return new Circle(this.x, this.y, this.r, this.sAngle, this.eAngle, this.counterclockwise)
  }
  /**
   * @description: 获取两点间距离
   * @param {type} 
   * @return {type} 
   */
  static getDistance(point1, point2) {
    return Math.pow(Math.pow(point2[0] - point1[0], 2) + Math.pow(point2[1] - point1[1], 2), 1 / 2);
  }

  getFormShowPosition() {
    return [this.x + this.r, this.y];
  }

  move(x = 0, y = 0, opts) {
    let beyond
    if (opts) {
      if (opts.beyond) {
        beyond = opts.beyond
      }
    }
    let r = this.r;
    if (beyond) {
      if (this.x + x - r < beyond.xmin || this.x + x + r > beyond.xmax) {
        if (this.x + x - r < beyond.xmin) {
          this.x = beyond.xmin + r - x;
        }
        if (this.x + x + r > beyond.xmax) {
          this.x = beyond.xmax - r - x;
        }
      } else {
        this.x += x;
      }

      if (this.y + y - r < beyond.ymin || this.y + y + r > beyond.ymax) {
        if (this.y + y - r < beyond.ymin) {
          this.y = beyond.ymin + r - y;
        }
        if (this.y + y + r > beyond.ymax) {
          this.y = beyond.ymax - r - y;
        }
      } else {
        this.y += y;
      }
    } else {
      this.x += x;
      this.y += y;
    }
    
  }

  getVertex(pixelCoordinate, tolerance) {
    let minR = this.r - 1 / 2 * tolerance;
    let maxR = this.r + 1 / 2 * tolerance;
    let l = Circle.getDistance(pixelCoordinate, [this.x, this.y]);
    if (!(l >= minR && l <= maxR)) {
      return null;
    }
    let [cx, cy] = pixelCoordinate;
    let [ox, oy] = [this.x, this.y];
    let px, py;
    if (cy > oy) {
      py = oy + this.r * Math.abs(oy - cy) / l;
    } else {
      py = oy - this.r * Math.abs(oy - cy) / l;
    }
    if (cx > ox) {
      px = ox + Math.sqrt(Math.pow(this.r, 2) - Math.pow(py - oy, 2));
    } else {
      px = ox - Math.sqrt(Math.pow(this.r, 2) - Math.pow(py - oy, 2));
    }
    return [px, py];
  }

  updateCoordinatesForModification(coords, extent) {
    let newR = Circle.getDistance([this.x, this.y], coords);
    let coordinates = this.getCoordinates();
    if (newR <= 0) {
      return coordinates;
    }
    if (extent) {
      if (
        this.x - newR >= 0 &&
        this.x + newR <= extent[2] &&
        this.y - newR >= 0 &&
        this.y + newR <= extent[3]
      ) {
        coordinates[2] = newR;
      } else {
        let r1 = this.x;
        let r2 = extent[2] - this.x;
        let r3 = this.y;
        let r4 = extent[3] - this.y;
        coordinates[2] = Math.min.apply(null, [r1, r2, r3, r4]);
      }
    } else {
      coordinates[2] = newR;
    }
    return coordinates;
  }

  /**
   * 获取默认绘制样式
   *
   * @method getDefaultStyleFunction
   * @returns {Function}
   */
  getDefaultStyleFunction() {
    const styles = Style.createDefaultEditing()
    return function (feature) {
      return styles[feature.geometry.geometryType]
    }
  }

  intersectPoint(x, y, tolerance = 3, type = 1) {
    const points = [
      [this.x - this.r, this.y], [this.x + this.r, this.y], [this.x, this.y - this.r], [this.x, this.y + this.r]
    ]
    
    if(type === 1) {
      const point = points.find(item => {
        const pointDistance = distance([x,y], item)
        if (pointDistance <= tolerance) {
          return true
        }
      })
      return point;
    }

    if(type === 2) {
      const { point1, point2 } = getLineCircleIntersection({x: this.x, y: this.y}, {x: this.x, y: this.y}, {x, y}, this.r);
      const p1 = [point1.x, point1.y];
      const p2 = [point2.x, point2.y];
      const distance1 = distance([x,y], p1);
      const distance2 = distance([x,y], p2);
      const min = Math.min(distance1, distance2);
      if(min <= tolerance) {
        const point = min === distance1 ? p1 : p2;
        return point;
      }
    }
  }
}
